-- Dbase
-- Create by weism
-- 相当于LPC的级联数组

require("game/logic/base/ExpressMapping");

Dbase = {
    dbase = {}, -- 数据
    temp_dbase = {}, -- 临时数据
    cb = {},    -- 触发器
};
Dbase.__index = Dbase;

-- 相加操作
function Dbase.__add(a, b)
    local r = Dbase.new();
    for k, v in pairs(a.dbase) do
        r.dbase[k] = v;
    end
    for k, v in pairs(b.dbase) do
        r.dbase[k] = v;
    end

    for i = 1, #a.cb do
        table.insert(r.cb, a.cb[i]);
    end
    for i = 1, #b.cb do
        table.insert(r.cb, b.cb[i]);
    end

    return r;
end

-- 创建
function Dbase.new(data)
    local self = {};
    setmetatable(self, Dbase);
    if data ~= nil and type(data) == "table" then
        self.dbase = data;
        self.temp_dbase = {};
    else
        self.dbase = {};
        self.temp_dbase = {};
    end
    self.cb = {};
    return self;
end

-- 取得该对象的描述字符串
function Dbase:get_ob_id()
    return "Dbase";
end

-- 替换数据
function Dbase:replace(data)
    self.dbase = data;
end

-- 吸收数据
function Dbase:aborb(data)
    for k, v in pairs(data) do
        self.dbase[k] = v;
        self:triggerField(k);
    end
end

-- 设置数据
-- 若传入三个参数，则前两个为两级路径的值
function Dbase:set(path, k, v)
    local dbase = self.dbase;
    if v then
        -- 两级路径
        dbase[path] = dbase[path] or {};
        dbase[path][k] = v;
    else
        local flag = string.find(path, "/");
        if flag then
            assert(false, "dbase:set 不允许传入级联key！");
            self:setEx(path, k);
            return;
        else
            dbase[path] = k;
        end
    end

    self:triggerField(path);
end

-- 设置数据，可以传入级联路径
function Dbase:setEx(path, v)
    expressSet(path, self.dbase, v);
    self:triggerFieldEx(path);
end

-- 检索数据
-- 若需要查询两级路径，则必须传入三个参数
function Dbase:query(path, path2, default)
    local dbase = self.dbase;
    if default ~= nil then
        if type(dbase[path]) ~= "table" then
            return default;
        end
        return dbase[path][path2] or default;
    else
        local flag = string.find(path, "/");
        if flag then
            assert(false, "dbase:query 不允许传入级联key！");
            return self:queryEx(path, path2);
        else
            return dbase[path] or path2;
        end
    end
end

-- 检索数据，可以传入级联路径
function Dbase:queryEx(path, default)
    return expressQuery(path, self.dbase, default);
end

-- 删除数据
-- 若传入两个参数，则为两级路径的值
function Dbase:delete(path, path2)
    if path == nil or path == "" then
        self.dbase = {};
    else
        if path2 then
            if type(self.dbase[path]) ~= "table" then
                return;
            end
            self.dbase[path][path2] = nil;
        else
            local flag = string.find(path, "/");
            if flag then
                assert(false, "dbase:delete 不允许传入级联key！");
                return self:deleteEx(path);
            else
                self.dbase[path] = nil;
            end
        end

        self:triggerField(path);
    end
end

-- 删除数据，可以传入级联路径
function Dbase:deleteEx(path)
    if path == nil or path == "" then
        self.dbase = {};
    else
        expressDelete(path, self.dbase);
        self:triggerFieldEx(path);
    end
end

-- 设置临时数据
-- 若传入三个参数，则前两个为两级路径的值
function Dbase:setTemp(path, k, v)
    local temp_dbase = self.temp_dbase;
    if v then
        -- 两级路径
        temp_dbase[path] = temp_dbase[path] or {};
        temp_dbase[path][k] = v;
    else
        local flag = string.find(path, "/");
        if flag then
            assert(false, "dbase:setTemp 不允许传入级联key！");
            self:setTempEx(path, k);
            return;
        else
            temp_dbase[path] = k;
        end
    end
    self:triggerField(path);
end

-- 设置数据，可以传入级联路径
function Dbase:setTempEx(path, v)
    expressSet(path, self.temp_dbase, v);
    self:triggerFieldEx(path);
end

-- 删除临时数据
-- 若传入两个参数，则为两级路径的值
function Dbase:deleteTemp(path, path2)
    if path == nil or path == "" then
        self.temp_dbase = {};
    else
        if path2 then
            if type(self.temp_dbase[path]) ~= "table" then
                return;
            end
            self.temp_dbase[path][path2] = nil;
        else
            local flag = string.find(path, "/");
            if flag then
                assert(false, "dbase:deleteTemp 不允许传入级联key！");
                return self:deleteTempEx(path);
            else
                self.temp_dbase[path] = nil;
            end
        end

        self:triggerField(path);
    end
end

-- 删除数据，可以传入级联路径
function Dbase:deleteTempEx(path)
    if path == nil or path == "" then
        self.temp_dbase = {};
    else
        expressDelete(path, self.temp_dbase);
        self:triggerFieldEx(path);
    end
end

-- 检索临时数据
-- 若需要查询两级路径，则必须传入三个参数
function Dbase:queryTemp(path, path2, default)
    local temp_dbase = self.temp_dbase;
    if default ~= nil then
        if type(temp_dbase[path]) ~= "table" then
            return default;
        end
        return temp_dbase[path][path2] or default;
    else
        local flag = string.find(path, "/");
        if flag then
            assert(false, "dbase:queryTemp 不允许传入级联key！");
            return self:queryTempEx(path, path2);
        else
            return temp_dbase[path] or path2;
        end
    end
end

-- 检索数据，可以传入级联路径
function Dbase:queryTempEx(path, default)
    return expressQuery(path, self.temp_dbase, default);
end

-- 注册个触发器
function Dbase:registerCb(name, fields, f)
    local arr = {};
    if (type(fields) == "table") then
        arr = fields;
    elseif (type(fields) == "string") then
        table.insert(arr, fields);
    end

    for i = 1, #arr do
        if self.cb[arr[i]] == nil then
            self.cb[arr[i]] = {};
        end

        if self.cb[arr[i]][name] ~= nil then
            error("触发器已经存在了，不能重复注册");
        else
            self.cb[arr[i]][name] = f;
        end
    end
end

-- 反注册
function Dbase:removeCb(name, fields)
    local arr = {};
    if (type(fields) == "table") then
        arr = fields;
    elseif (type(fields) == "string") then
        table.insert(arr, fields);
    end

    for i = 1, #arr do
        if self.cb[arr[i]] ~= nil then
           self.cb[arr[i]][name] = nil;
        end
    end
end

-- 调用触发器
function Dbase:triggerField(path)
    if DEBUG_MODE == 1 then
        assert(not string.find(path, "/"), "dbase:triggerField 不允许传入级联key！");
    end

    local m = self.cb[path];
    if m ~= nil then
        for k, v in pairs(m) do
            v();
        end
    end

    -- 公共数据触发器
    m = self.cb["*"];
    if m ~= nil then
        for k, v in pairs(m) do
            v(path);
        end
    end
end

-- 调用触发器，允许级联路径
function Dbase:triggerFieldEx(path)
    local m = self.cb[path];
    if m ~= nil then
        for k, v in pairs(m) do
            v();
        end
    end

    -- 根节点的触发器
    local index = string.find(path, "/");
    if index then
        m = self.cb[string.sub(path, 1, index - 1)];
        if m ~= nil then
            for k, v in pairs(m) do
                v();
            end
        end
    end

    -- 公共数据触发器
    local m = self.cb["*"];
    if m ~= nil then
        local index = string.find(path, "/");
        local key = path;

        if index then
            key = string.sub(path, 1, index - 1);
        end
        for k, v in pairs(m) do
            v(key);
        end
    end
end
